package com.lingyuan.oms.aspect;


import com.lingyuan.common.core.exception.ServiceException;
import com.lingyuan.oms.annotation.Idempotent;
import com.lingyuan.oms.constant.OrderConstant;
import com.lingyuan.oms.domain.param.CreateOrderParam;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/* *
 * @Title: IdempotentAspect
 * @Author: DELL
 * @Date: 2024-10-08 12:11:19
 * @Description: 幂等性切面
 */
@Aspect
@Component
public class IdempotentAspect {

    private static final Logger logger = LoggerFactory.getLogger(IdempotentAspect.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ParameterNameDiscoverer parameterNameDiscoverer;

    @Around("@annotation(idempotent)")
    public Object handleIdempotent(ProceedingJoinPoint joinPoint, Idempotent idempotent) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 获取方法参数
        Object[] args = joinPoint.getArgs();
        // 获取方法参数名
        String[] paramNames = parameterNameDiscoverer.getParameterNames(method);

        // 根据注解配置获取幂等性字段
        String idempotentFieldName = idempotent.value();

        // 检查是否指定了幂等性参数名
        if (idempotentFieldName.isEmpty()) {
            throw new IllegalArgumentException("请指定幂等性检查的参数名");
        }

        // 获取幂等性检查的参数值
        Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < paramNames.length; i++) {
            paramMap.put(paramNames[i], args[i]);
        }

        // 输出参数映射表
        logger.info("Parameters: {}", paramMap);

        Object paramObject = paramMap.values().toArray()[0];
        if (!(paramObject instanceof CreateOrderParam)) {
            throw new IllegalArgumentException("未找到指定的幂等性参数：" + idempotentFieldName);
        }

        CreateOrderParam createOrderParam = (CreateOrderParam) paramObject;

        // 获取幂等性检查的参数值
        Object idempotentFieldValue = createOrderParam.getToken();

        if (idempotentFieldValue == null) {
            throw new IllegalArgumentException("未找到指定的幂等性参数：" + idempotentFieldName);
        }

        // 构造 key
        String key = OrderConstant.CONFIRM_THE_ORDER + idempotentFieldValue;

        // 输出幂等性字段值
        logger.info("Idempotent Field Value: {}", idempotentFieldValue);

        // 检查 key 是否存在
        if (stringRedisTemplate.hasKey(key)) {
            // 删除 key 表示幂等性验证通过
            stringRedisTemplate.delete(key);
            return joinPoint.proceed();
        } else {
            // 抛出异常
            throw new ServiceException("请勿重复提交");
        }
    }
}
